package com.yc.utils;

import com.github.tobato.fastdfs.domain.fdfs.MetaData;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.exception.FdfsUnsupportStorePathException;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.Set;
import java.util.UUID;

/**
 * @author wanghong
 * @date 2020/01/09 11:16
 * 文件上传下载工具类
 * FastDFS 支持 给文件 分组 上传
 **/
@Slf4j
@Component
public class FileUtil {

    @Autowired
    private FastFileStorageClient storageClient;

    /**
     * 分组上传，需要事先配置FastDFS 添加新group
     *
     * @param groupName
     * @param file
     * @return
     */
    public String uploadFile(String groupName, MultipartFile file) {
        StorePath storePath = null;
        try {
            if (StringUtils.isEmpty(groupName)) {
                storePath = storageClient.uploadFile(file.getInputStream(), file.getSize(),
                        FilenameUtils.getExtension(file.getOriginalFilename()), null);
            } else {
                storePath = storageClient.uploadFile(groupName, file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()));
            }
        } catch (IOException e) {
            log.error("FileUtil.uploadFile exception:{}", e);
        }
        return getResAccessUrl(storePath);


    }

    /**
     * MultipartFile类型的文件上传ַ
     *
     * @param file
     * @return
     * @throws IOException
     */
    public String uploadFile(MultipartFile file) {
        return uploadFile(null, file);
    }

    /**
     * 普通的文件上传
     *
     * @param file
     * @return
     * @throws IOException
     */
    public String uploadFile(File file) throws IOException {
        FileInputStream inputStream = null;
        try {
            inputStream = new FileInputStream(file);
            StorePath path = storageClient.uploadFile(inputStream, file.length(),
                    FilenameUtils.getExtension(file.getName()), null);
            return getResAccessUrl(path);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    public String uploadLocalFile(String localFilePath) throws IOException {
        return uploadFile(new File(localFilePath));
    }

    /**
     * 带输入流形式的文件上传
     *
     * @param is
     * @param size
     * @param fileName
     * @return
     */
    public String uploadFileStream(InputStream is, long size, String fileName) {
        StorePath path = storageClient.uploadFile(is, size, fileName, null);
        return getResAccessUrl(path);
    }

    /**
     * 将一段文本文件写到fastdfs的服务器上
     *
     * @param content
     * @param fileExtension
     * @return
     */
    public String uploadFile(String content, String fileExtension) throws IOException {
        byte[] buff = content.getBytes(Charset.forName("UTF-8"));
        ByteArrayInputStream stream = null;
        try {
            stream = new ByteArrayInputStream(buff);
            StorePath path = storageClient.uploadFile(stream, buff.length, fileExtension, null);
            return getResAccessUrl(path);
        } finally {
            if (stream != null) {
                stream.close();
            }
        }
    }

    public String uploadFile(byte[] buff, String fileExtension) {
        ByteArrayInputStream stream = new ByteArrayInputStream(buff);
        StorePath path = storageClient.uploadFile(stream, buff.length, fileExtension, null);
        return getResAccessUrl(path);
    }

    /**
     * 返回文件上传成功后的地址名称ַ
     *
     * @param storePath
     * @return
     */
    private String getResAccessUrl(StorePath storePath) {
        String fileUrl = storePath.getFullPath();
        return fileUrl;
    }

    /**
     * 删除文件
     * <p>
     * API没有一次性清空所有文件
     * 若要清空所有文件, rm /var/fdfs/storage/data/* -rf 直接到存储目录删除
     * 然后 docker ps
     * docker restart 容器(storage/tracker)
     *
     * @param fileUrl
     */
    public void deleteFile(String fileUrl) {
        if (StringUtils.isEmpty(fileUrl)) {
            return;
        }
        try {
            StorePath storePath = StorePath.parseFromUrl(fileUrl);
            storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
        } catch (FdfsUnsupportStorePathException e) {
            log.warn(e.getMessage());
        }
    }

    public String upfileImage(InputStream is, long size, String fileExtName, Set<MetaData> metaData) {
        StorePath path = storageClient.uploadImageAndCrtThumbImage(is, size, fileExtName, metaData);
        return getResAccessUrl(path);
    }

    public void download(String filePath, String fileName, HttpServletResponse response) {
        int index = filePath.indexOf("/");
        String group = filePath.substring(0, index);
        String path = filePath.substring(index + 1);

        try {
            byte[] bytes = storageClient.downloadFile(group, path, new DownloadByteArray());
            //设置相应类型application/octet-stream        （注：applicatoin/octet-stream 为通用，一些其它的类型苹果浏览器下载内容可能为空）
            response.reset();
            response.setContentType("applicatoin/octet-stream");
            //设置头信息                 Content-Disposition为属性名  附件形式打开下载文件   指定名称  为 设定的fileName
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            // 写入到流
            ServletOutputStream out = response.getOutputStream();
            out.write(bytes);
            out.close();
        } catch (Exception e) {
            log.error("文件:{},路径:{}下载失败", fileName, filePath);
        }
    }

    public static void main(String[] args) throws Exception {
        String targetFile = "./files/51077864-eclipse-inst-win64exe/eclipse-inst-win64.exe";
        File f = new File(targetFile);
        System.out.println(f.exists());
        System.out.println(f.delete());

        // java.nio.file.FileSystemException 另一个程序正在使用此文件，进程无法访问
        System.out.println(Files.deleteIfExists(Paths.get(targetFile)));

        // 删除空目录
        String folder = "./files/1841-2sql";
        Path path = Paths.get(folder);
        long count = Files.list(path).count();
        System.out.println(count);
        if (count == 0) {
            Files.delete(path);
        }

        System.out.println(Files.exists(Paths.get("./files/1841-2sql")));
    }

    /**
     * TODO 获取FastDFS中存储的文件列表
     *
     * @return
     */
    public List<String> getFiles() {
        return null;
    }

    // TODO 计算文件的 md5Hash 判断两个文件是否相同
    public byte[] getFileByteArray(String filePath) {
        int index = filePath.indexOf("/");
        String group = filePath.substring(0, index);
        String path = filePath.substring(index + 1);
        byte[] bytes = storageClient.downloadFile(group, path, new DownloadByteArray());
        return bytes;
    }

    public static List<File> getAllFilePaths(File filePath, List<File> fileList) {
        File[] files = filePath.listFiles();
        if (files == null) {
            return fileList;
        }
        for (File f : files) {
            if (f.isDirectory()) {
                fileList.add(f);
                getAllFilePaths(f, fileList);
            } else {
                fileList.add(f);
            }
        }
        return fileList;
    }

    /**
     * JAVA将Base64转为文件并保存
     * @param base64
     * @param fileName
     * @param savePath
     */
    public static void base64ToFile(String base64, String fileName, String savePath) {
        File file = null;
        //创建文件目录
        String filePath = savePath;
        File dir = new File(filePath);
        if (!dir.exists() && !dir.isDirectory()) {
            dir.mkdirs();
        }
        BufferedOutputStream bos = null;
        java.io.FileOutputStream fos = null;
        try {
            byte[] bytes = Base64.getDecoder().decode(base64);
            file = new File(filePath + fileName);
            fos = new java.io.FileOutputStream(file);
            bos = new BufferedOutputStream(fos);
            bos.write(bytes);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @return java.lang.String
     * @Description 生成随机数
     * @Date 2019/11/1 10:36
     * @Param [length]
     **/
    public static String getRandomString(int length) {
        return UUID.randomUUID().toString().replaceAll("-","").substring(0,Math.max(length,32));
    }

}